#pragma once
#include"util.hpp"
#include"config.hpp"
#include<unordered_map>
#include<pthread.h>
namespace cloud
{
    class BackupInfo
    {
        public:
        bool pack_flag;
        size_t fsize;
        time_t mtime;
        time_t atime;
        std::string real_path;
        std::string pack_path;
        std::string url;
        BackupInfo()
        {}
        BackupInfo(const std::string& path)
        {
            NewBackupInfo(path);
        }
        bool NewBackupInfo(const std::string& path)
        {
            Util::FileUtil file(path);
            if(file.Exists())
            {
                Config* conf = Config::GetInstance();
                std::string pack_dir = conf->GetPackDir();
                std::string pack_suffix = conf->GetPackDileSuffix();
                std::string download_prefix = conf->GetDownloadPrefix();
                pack_flag = false;
                fsize = file.FileSize();
                mtime = file.LastModTime();
                atime = file.LastAccTime();
                real_path = path;
                pack_path = pack_dir + file.FileName() + pack_suffix;
                url = download_prefix+file.FileName();
            }
            else
            {
                std::cout << "BackupInfo err,file not exits"<< std::endl;
                return false;
            }
            return true;
        }
        
    };
    class DataManager
    {
        private:
        std::string _backup_file;
        pthread_rwlock_t _rwlock;
        std::unordered_map<std::string, BackupInfo> _table;

        public:
        DataManager()
        {
            _backup_file = Config::GetInstance()->GetBackupFile();
            pthread_rwlock_init(&_rwlock,nullptr);
            InitLoad();
        }
        ~DataManager()
        {
            pthread_rwlock_destroy(&_rwlock);
        }
        bool Insert(const BackupInfo& info)
        {
            pthread_rwlock_wrlock(&_rwlock);
            _table[info.url] = info;
            pthread_rwlock_unlock(&_rwlock);
            Storage();
            return true;
        }
        bool Update(const BackupInfo& info)
        {
            pthread_rwlock_wrlock(&_rwlock);
            _table[info.url] = info;
            pthread_rwlock_unlock(&_rwlock);
            Storage();
            return true;
        }
        bool GetOneByURL(const std::string& url, BackupInfo* info)
        {
            pthread_rwlock_rdlock(&_rwlock);
            std::unordered_map<std::string,BackupInfo>::iterator it = _table.find(url);
            if( it == _table.end())
            {
                pthread_rwlock_unlock(&_rwlock);
                return false;
            }
            else
            {
                *info = it->second;
            }
            pthread_rwlock_unlock(&_rwlock);
            return true;
        }
        bool GetOneByRealPath(const std::string& realpath, BackupInfo* info)
        {
            pthread_rwlock_rdlock(&_rwlock);
            std::unordered_map<std::string,BackupInfo>::iterator it = _table.begin();
            while(it != _table.end())
            {
                if(it->second.real_path == realpath)
                {
                    *info = it->second;
                    pthread_rwlock_unlock(&_rwlock);
                    return true;
                }
                it++;
            }

            pthread_rwlock_unlock(&_rwlock);
            return false;
        }
        bool GetAll(std::vector<BackupInfo>* arr)
        {
            pthread_rwlock_rdlock(&_rwlock);
            std::unordered_map<std::string,BackupInfo>::iterator it = _table.begin();
            while(it != _table.end())
            {
                arr->push_back(it->second);
                it++;
            }

            pthread_rwlock_unlock(&_rwlock);
            return true;
        }
        bool Storage()
        {
            std::vector<BackupInfo> arr;
            GetAll(&arr);
            Json::Value root;
            for(const auto& it : arr)
            {
                Json::Value item;
                item["pack_flag"] = it.pack_flag;
                item["fsize"] = static_cast<Json::UInt>(it.fsize);
                item["atime"] = static_cast<Json::UInt64>(it.atime);
                item["mtime"] = static_cast<Json::UInt64>(it.mtime);
                item["real_path"] = it.real_path;
                item["pack_path"] = it.pack_path;
                item["url"] = it.url;
                root.append(item);
            }
            std::string body;
            Util::JsonUtil::Serialize(root,&body);


            Util::FileUtil f(_backup_file);
            f.SetContent(body);
            return true;
        }
        bool InitLoad()
        {
            Util::FileUtil f(_backup_file);
            if(f.Exists()==false)
            {
                return true;
            }
            std::string body;
            f.GetContent(&body);
            Json::Value root;
            Util::JsonUtil::UnSerialize(&root,body);
            for(int i = 0;i<root.size();i++)
            {
                BackupInfo info;

                info.pack_flag = root[i]["pack_flag"].asBool();
                info.fsize = root[i]["fsize"].asUInt64();
                info.atime = root[i]["atime"].asInt64();
                info.mtime = root[i]["mtime"].asInt64();
                info.pack_path = root[i]["pack_path"].asString();
                info.real_path = root[i]["real_path"].asString();
                info.url = root[i]["url"].asString();
                Insert(info);
            }
            return true;
        }
    };



}